/**
 * 手撸实现 Promise 思路：
 * 
 * 1、Promise 是一个类，参数是一个执行器（函数），传入时，执行器会立即执行
 *    所以 constructor 接收函数参数，并执行
 * 
 * 
 * 2、Promise 有三个状态 pending、fulfilled、rejected；初始状态为 pending
 *    传入的执行器接收两个函数参数 resolve、reject，作用是改变 Promise 的状态
 *        resolve()：pending ---> fulfilled
 *        reject()：pending ---> rejected
 *        且状态一旦被改变，则不能再更改
 * 
 * 
 * 3、所以 Promise 中要有 resolve、reject、status(状态：pending、fulfilled、rejected)，且它们是 Promise 的内部属性
 *    定义 resolve 和 reject 使用箭头函数，是为了保证 this 的指向是该函数的调用者，即该 Promise
 *    
 *    resolve 和 reject 分别会将 status 改为 fulfilled 和 rejected；
 *    为保证 resolve、reject 任意一个被调用将 status 改变后，status 就不能再被更改
 *    所以其中最开始需要加入判断 status 是否已经不是 pending，若不是，则 return，不执行后续代码
 * 
 *    另，status 在 Promise 经常使用，相比每次写字符串值，设置常量保存值更方便，且使用时有代码提示
 * 
 * 
 * 4、Promise 有个 then 的实例方法，其中有两个回调函数作为参数（成功回调、失败回调）
 *    then 中需要判断 status 成功与否，来觉得使用哪个回调
 *    then 中的回调接受参数分别为：成功值、错误原因，这两个值来自于执行器中调用 resolve 和 reject 传入的参数
 *    所以，resolve 和 reject 需要分别把传入的值（value、reason）保存，并在 then 执行回调时传入
 * 
 * 
 * 5、若执行器中有异步，则 then 中需要判断 status 仍是 pending 的状态
 *    pending 时，resolve/reject 都还未被执行器调用，且 value、reason 都未有值
 *    则此时，需要将 then 中的回调(successCallback, failCallback)暂时存起来，并将其分别放在resolve、reject执行
 * 
 * 
 * 6、关于同一个 Promise 的实例的 then 方法多次调用
 *    同步时：
 *        第一次使用 then 时，status 已经被改变为 fulfilled/rejected，所以直接执行第一个 then 的相应回调
 *        对于后续的 n 个 then，因为 status 已经被确定，所以会直接实行这些 then 中的相应回调
 *    异步时：
 *        因为执行器中有异步，使用 then 方法时，status 还是 pending 状态，按照第5步的方法暂存 then 中的回调，只会存第一个 then 的回调
 *        为了存所有 then 的回调，需要将保存相应回调的属性变成数组形式
 *        在 pending 状态时，把所有回调 push 进相应的暂存属性中
 *        然后在 resolve/reject 中，依次执行暂存回调数组中的回调函数
 * 
 * 
 * 7、then的链式调用和返回值传递
 *      (1)、要达成 then 的链式调用，则 then 需要返回一个新的 Promise 对象，所以 then 中需要 new 一个 Promise 对象来返回
 *           这个将被返回的新的 Promise 的执行器是立即调用的，而原本的 then 中的状态判断和回调使用等也是立即调用，所以可以把这部分放入执行器中
 * 
 *      (2)、返回的新的 Promise 对象要使用 then 方法，就需要在其执行器中调用 resolve/reject 来确定状态
 *           
 *           上一个 then 的回调中可以有返回值，并且可以把这个返回值传递给下一个 then，且这个返回值可以是 '普通值'，也可以是 'Promise 对象'
 *           
 *           '普通值'，直接调用要返回的新的 Promise 的 resolve，把值传递给下一个 then
 *           'Promise 对象'，则需先查看该 Promise 对象的状态（使用 then 方法来判断），
 *                    若成功，调用要返回的新的 Promise 的 resolve，把成功值传递给下一个 then
 *                    若失败，调用要返回的新的 Promise 的 reject，把失败的原因传递给下一个 then
 * 
 *           因为根据原本 Promise 的 then 链式调用的结果来看，Promise 执行器中执行 reject，会在第一个 then 中调用失败回调，但后续的 then 不会
 *           即 Promise 的 then 中的失败回调，应只因本 Promise 调用 reject，后才执行
 *           所以，除非这个要被返回的新的 Promise 中本身除了错误才使用 reject 以外，其他的都用 resolve
 * 
 *      (3)、then 不能返回当前这个 then 方法返回的 Promise 对象，否则就出现了 Promise 对象的循环调用，所以需要判断，并抛出错误
 * 
 * 
 * 8、then() 的参数变为可选参数
 *      根据原本的 Promise 来看，若 then() 中不传递回调，则表示该 then 不对成功或失败的结果进行处理
 *      然后无参数的 then 将成功或失败的结果传递给下一个 then 进行处理
 *      而无参数的 then() 相当于 then(res => res, err => {throw err})
 *      
 *      所以，在我们自己的 MyPromise 的 then 方法中，对回调参数先进行判断是否存在
 *      所不存在，则用 res => res / err => {throw err} 定义相应的回调即可
 * 
 *      另，因为使用了 throw err 抛出异常的操作，所以在 then 的执行的回调中，需要捕获异常，并调用 reject，如此才能把异常传递给后续的 then
 *      所以，这里用 try{}catch(error){} 语句来处理执行回调代码的异常
 * 
 * 
 * 9、利用 try{}catch(error){} 来处理 MyPromise 类中，执行代码的异常，捕获异常则调用 reject
 * 
 * 
 * 10、Promise.all()
 *     因为 Promise 直接调用 all() 方法，而不是其实例调用，所以 all() 为 Promise 的静态方法
 *     
 *     all() 的参数为数组，数组项为 普通值 或者 Promise 对象
 *     all() 后面可以直接调用 then，所以 Promise.all() 的返回值是个 Promise 对象
 *     
 *     这里的 then 的成功回调，会在传入 Promise.all() 里的数组里的所有项执行完后才调用执行
 *         成功回调里传入的参数也是一个数组，按照传入时的顺序排列
 *         若之前传入的项是普通值，则返回普通值
 *         若之前传入的项是 Promise 对象，则返回该 Promise 成功后的值
 * 
 *    这里的 then 的失败回调，会在任意一个传入项失败时调用，失败回调里的参数就是那个失败项的失败原因
 * 
 * 
 * 11、Promise.resolve()
 *     resolve 为静态方法
 *     根据原本 Promise.resolve() 来看
 *     传入参数可为 普通值 / Promise 对象
 *         普通值：返回一个状态为成功的 Promise 对象，该 普通值 即为 then 方法中成功回调的参数
 *         Promise 对象：原样返回这个 Promise 对象
 * 
 * 
 * 12、finally 方法
 *     finally 为实例调用的方法，所以是 Promise 原型对象上的方法
 *     接收一个回调函数为参数，无论 Promise 是否成功, 都会执行
 *     finally 后面可链式调用 then 方法，该 then 中可拿到当前这个 Promise 对象返回的结果
 *     finally 的回调中可有返回值，若该返回的是个有异步的操作，则后面的 then 需要等异步结束后再执行
 * 
 * 
 * 13 catch 方法
 *    catch 为实例调用的方法，所以是 Promise 原型对象上的方法
 *    处理当前这个 Promise 的状态为失败的情况
 *    但 Promise 调用的 then 中没有传入失败回调，则错误会传递给 catch
 */